#if !defined(AFX_RTFBITMAP_H__20050305_E8C3_C01F_71A8_0080AD509054__INCLUDED_)
#define AFX_RTFBITMAP_H__20050305_E8C3_C01F_71A8_0080AD509054__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000


class CRtfBitmap
{
public:
	LPOLEOBJECT	m_lpObject;
	LPSTORAGE m_lpStorage;
	LPOLECLIENTSITE m_lpClientSite;

   CRtfBitmap()
   {
	   m_lpObject = NULL;
	   m_lpStorage = NULL;
	   m_lpClientSite = NULL;
   }
   ~CRtfBitmap()
   {
      Release();
   }

   void Release()
   {
      if( m_lpObject != NULL ) {
		   m_lpObject->Release();
		   m_lpObject = NULL;
	   }
      if( m_lpStorage != NULL ) {
		   m_lpStorage->Release();
		   m_lpStorage = NULL;
	   }
      if( m_lpClientSite != NULL ) {
		   m_lpClientSite->Release();
		   m_lpClientSite = NULL;
	   }
   }

   BOOL CreateFromBitmap(HWND hWnd, LPRICHEDITOLE pRichEditOle, HBITMAP hBitmap)
   {
	   ATLASSERT(m_lpObject==NULL);     // one time only
	   ATLASSERT(m_lpStorage==NULL);
	   ATLASSERT(m_lpClientSite==NULL);

      LPLOCKBYTES lpLockBytes = NULL;
	   //CLSID clsid = CLSID_NULL;
	   OLERENDER render = OLERENDER_DRAW;
	   CLIPFORMAT cfFormat = 0;
	   LPFORMATETC lpFormatEtc = NULL;

      if( !::OpenClipboard(hWnd) ) return FALSE;
      ::EmptyClipboard();
      ::SetClipboardData(CF_BITMAP, hBitmap);
      ::CloseClipboard();

      LPDATAOBJECT pDataObject = NULL;
      if( FAILED( ::OleGetClipboard(&pDataObject) ) ) return FALSE;

	   SCODE sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);
	   if( sc != S_OK ) return FALSE;
	   ATLASSERT(lpLockBytes!=NULL);

	   sc = ::StgCreateDocfileOnILockBytes(lpLockBytes, STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &m_lpStorage);
	   if( sc != S_OK ) {
		   lpLockBytes = NULL;
		   return FALSE;
	   }
	   ATLASSERT(m_lpStorage!=NULL);

	   // Fill in FORMATETC struct
      FORMATETC formatEtc = { 0 };
	   lpFormatEtc = &formatEtc;
	   lpFormatEtc->cfFormat = cfFormat;
	   lpFormatEtc->ptd = NULL;
	   lpFormatEtc->dwAspect = DVASPECT_CONTENT;
	   lpFormatEtc->lindex = -1;
	   lpFormatEtc->tymed = TYMED_NULL;

	   // Attempt to create the object
	   pRichEditOle->GetClientSite(&m_lpClientSite);

      sc = ::OleCreateStaticFromData(pDataObject,
		   IID_IUnknown, OLERENDER_DRAW, lpFormatEtc, m_lpClientSite, m_lpStorage,
		   (void**) &m_lpObject);
	   if( sc != S_OK ) return FALSE;

	   // m_lpObject is currently an IUnknown, convert to IOleObject
	   if( m_lpObject != NULL ) {
		   LPUNKNOWN lpUnk = m_lpObject;
		   lpUnk->QueryInterface(IID_IOleObject, (void**) &m_lpObject);
		   lpUnk->Release();
		   if( m_lpObject == NULL ) return FALSE;
	   }

	   // All items are "contained" -- this makes our reference to this object
	   //  weak -- which is needed for links to embedding silent update.
      ::OleSetContainedObject(m_lpObject, TRUE);

      pDataObject->Release();

	   return TRUE;
   }

   BOOL CreateFromFile(LPRICHEDITOLE pRichEditOle, LPCTSTR lpszFileName)
   {
	   USES_CONVERSION;

	   ATLASSERT(m_lpObject==NULL);     // one time only
	   ATLASSERT(m_lpStorage==NULL);
	   ATLASSERT(m_lpClientSite==NULL);

      LPLOCKBYTES lpLockBytes = NULL;
	   CLSID clsid = CLSID_NULL;
	   OLERENDER render = OLERENDER_DRAW;
	   CLIPFORMAT cfFormat = 0;
	   LPFORMATETC lpFormatEtc = NULL;

	   SCODE sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);
	   if( sc != S_OK ) return FALSE;
	   ATLASSERT(lpLockBytes!=NULL);

	   sc = ::StgCreateDocfileOnILockBytes(lpLockBytes, STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &m_lpStorage);
	   if (sc != S_OK) {
		   lpLockBytes = NULL;
		   return FALSE;
	   }
	   ATLASSERT(m_lpStorage!=NULL);

	   // Fill in FORMATETC struct
      FORMATETC formatEtc = { 0 };
	   lpFormatEtc = &formatEtc;
	   lpFormatEtc->cfFormat = cfFormat;
	   lpFormatEtc->ptd = NULL;
	   lpFormatEtc->dwAspect = DVASPECT_CONTENT;
	   lpFormatEtc->lindex = -1;
	   lpFormatEtc->tymed = TYMED_NULL;

	   // Attempt to create the object
	   pRichEditOle->GetClientSite(&m_lpClientSite);

	   sc = ::OleCreateFromFile(clsid, T2COLE(lpszFileName),
		   IID_IUnknown, OLERENDER_DRAW, lpFormatEtc, m_lpClientSite, m_lpStorage,
		   (void**) &m_lpObject);
	   if( sc != S_OK ) return FALSE;

	   // m_lpObject is currently an IUnknown, convert to IOleObject
	   if( m_lpObject != NULL ) {
		   LPUNKNOWN lpUnk = m_lpObject;
		   lpUnk->QueryInterface(IID_IOleObject, (void**) &m_lpObject);
		   lpUnk->Release();
		   if( m_lpObject == NULL ) return FALSE;
	   }

	   // All items are "contained" -- this makes our reference to this object
	   //  weak -- which is needed for links to embedding silent update.
      ::OleSetContainedObject(m_lpObject, TRUE);

	   return TRUE;
   }

   BOOL Insert(HWND hWnd, LPRICHEDITOLE pRichEditOle)
   {
      CRichEditCtrl m_ctrlRich = hWnd;
      ATLASSERT(::IsWindow(hWnd));
     
      REOBJECT reobject;
      ::ZeroMemory(&reobject, sizeof(REOBJECT));
      reobject.cbStruct = sizeof(REOBJECT);
      CLSID clsid;
      SCODE sc = m_lpObject->GetUserClassID(&clsid);
      if( sc != S_OK ) return FALSE;
      reobject.clsid = clsid;
      reobject.cp = REO_CP_SELECTION;
      reobject.dvaspect = DVASPECT_CONTENT;
      reobject.dwFlags = REO_RESIZABLE | REO_BELOWBASELINE;
      reobject.dwUser = 0;
      reobject.poleobj = m_lpObject;

      ATLASSERT(m_lpClientSite!=NULL);
      reobject.polesite = m_lpClientSite;
      ATLASSERT(m_lpStorage!=NULL);
      reobject.pstg = m_lpStorage;
      SIZEL sizel;
      sizel.cx = sizel.cy = 0;
      reobject.sizel = sizel;

      m_ctrlRich.SendMessage(EM_SETSEL, 0, (LPARAM) -1);
      DWORD dwStart = 0; 
      DWORD dwEnd = 0;
      m_ctrlRich.SendMessage(EM_GETSEL, (WPARAM) &dwStart, (LPARAM) &dwEnd);
      m_ctrlRich.SendMessage(EM_SETSEL, dwEnd + 1, dwEnd + 1);

	   m_ctrlRich.ReplaceSel(_T("\r\n"), TRUE);

      // Finally
      pRichEditOle->InsertObject(&reobject);

      m_ctrlRich.SendMessage(EM_SCROLLCARET, (WPARAM)0, (LPARAM)0);
      return TRUE;
   }
};


#endif // !defined(AFX_RTFBITMAP_H__20050305_E8C3_C01F_71A8_0080AD509054__INCLUDED_)

